#include "MqttClient.h"
#include "esp_log.h"
#include "cJSON.h"
#include "MqttClientDefine.h"
#include "utils/utils.h"
static const char *TAG = "MqttClient";

typedef struct MqttClient
{
    esp_mqtt_client_handle_t client;
    char mqttHost[128];
    int mqttPort;
    char user_name[128];
    char password[128];
    char topic[128];

    bool mqttConnected; /// 是否连接上
    mqtt_connect_callback_t mqtt_connect_callback;
    mqtt_recv_msg_callback_t mqtt_recv_msg_callback;

    EventGroupHandle_t wifi_event_group;
} MqttClient;

void handle_phone_MOVE_CAR(MqttClient *handle, MessageType messageType, const cJSON *dataObj);

// Initializes the MQTT client handle
MqttClient *mqtt_client_init(mqtt_connect_callback_t connect_callback, mqtt_recv_msg_callback_t recv_msg_callback)
{
    MqttClient *handle = (MqttClient *)calloc(1, sizeof(MqttClient));
    if (!handle)
    {
        ESP_LOGE(TAG, "Failed to allocate memory for MQTT client handle");
        return NULL;
    }
    memset(handle, 0, sizeof(MqttClient)); // 关键：保证 bool 和指针都干净
    if (connect_callback)
        handle->mqtt_connect_callback = connect_callback;

    if (recv_msg_callback)
        handle->mqtt_recv_msg_callback = recv_msg_callback;
    return handle;
}

/// 设置连接回调
void MqttClient_set_connect_callback(MqttClient *handle, mqtt_connect_callback_t cb)
{
    if (!handle)
        return;
    handle->mqtt_connect_callback = cb;
}

/// 设置接收消息回调
void MqttClient_set_recv_msg_callback(MqttClient *handle, mqtt_recv_msg_callback_t cb)
{
    if (!handle)
        return;
    handle->mqtt_recv_msg_callback = cb;
}

// Starts the MQTT client and connects to the broker
void mqtt_client_start(MqttClient *handle, const char *mqttHost, const char *user_name, const char *password, int mqttPort, const char *topic)
{
    if (!handle)
    {
        ESP_LOGE(TAG, "Invalid MQTT client handle");
        return;
    }
    mqtt_client_stop(handle);
    if (!mqttHost)
    {
        return;
    }
    if (mqttPort == 0)
    {
        return;
    }

    strncpy(handle->mqttHost, mqttHost, sizeof(handle->mqttHost) - 1);
    handle->mqttHost[sizeof(handle->mqttHost) - 1] = '\0';

    handle->mqttPort = mqttPort;
    if (user_name != NULL)
    {
        strncpy(handle->user_name, user_name, sizeof(handle->user_name) - 1);
        handle->user_name[sizeof(handle->user_name) - 1] = '\0';
    }
    if (password != NULL)
    {
        strncpy(handle->password, password, sizeof(handle->password) - 1);
        handle->password[sizeof(handle->password) - 1] = '\0';
    }
    if (topic != NULL)
    {
        strncpy(handle->topic, topic, sizeof(handle->topic) - 1);
        handle->topic[sizeof(handle->topic) - 1] = '\0';
    }
    char uri[256];
    snprintf(uri, sizeof(uri), "mqtt://%s:%d", handle->mqttHost, handle->mqttPort);

    esp_mqtt_client_config_t cfg = {
        .broker.address.uri = uri,
        .session.keepalive = MQTT_KEEPALIVE_SEC, // Keep alive for 25 seconds
        .buffer.size = MQTT_BUFFER_SIZE,         // Buffer size
    };

    if (user_name && strlen(user_name) > 0)
    {
        cfg.credentials.username = user_name;
    }
    if (password && strlen(password) > 0)
    {
        cfg.credentials.authentication.password = password;
    }

    handle->client = esp_mqtt_client_init(&cfg);
    ESP_ERROR_CHECK(esp_mqtt_client_register_event(handle->client, ESP_EVENT_ANY_ID, mqtt_client_event_handler, handle));
    ESP_ERROR_CHECK(esp_mqtt_client_start(handle->client));
}

// MQTT event handler callback function
static void mqtt_client_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    MqttClient *handle = (MqttClient *)handler_args;
    esp_mqtt_event_handle_t event = event_data;
    esp_mqtt_client_handle_t client = event->client;

    switch ((esp_mqtt_event_id_t)event_id)
    {
    case MQTT_EVENT_CONNECTED:
        handle->mqttConnected = true;
        ESP_LOGI(TAG, "MQTT connected");
        esp_mqtt_client_subscribe(client, handle->topic, 1);
        break;

    case MQTT_EVENT_DISCONNECTED:
        handle->mqttConnected = false;
        ESP_LOGW(TAG, "MQTT disconnected");
        break;

    case MQTT_EVENT_SUBSCRIBED:
        ESP_LOGI(TAG, "Subscribed, msg_id=%d", event->msg_id);
        break;

    case MQTT_EVENT_UNSUBSCRIBED:
        ESP_LOGI(TAG, "Unsubscribed, msg_id=%d", event->msg_id);
        break;

    case MQTT_EVENT_PUBLISHED:
        ESP_LOGI(TAG, "Published, msg_id=%d", event->msg_id);
        break;

    case MQTT_EVENT_DATA:
        // event->topic/event->topic_len and event->data/event->data_len are NOT null-terminated

        break;

    case MQTT_EVENT_ERROR:
        ESP_LOGE(TAG, "MQTT event error");
        break;

    default:
        ESP_LOGD(TAG, "Other MQTT event id:%d", event->event_id);
        break;
    }

    if (event_id == MQTT_EVENT_DATA)
    {
        char topic[128] = {0};
        int tlen = event->topic_len < (int)sizeof(topic) - 1 ? event->topic_len : (int)sizeof(topic) - 1;
        memcpy(topic, event->topic, tlen);
        ESP_LOGI(TAG, "Incoming [%s]: %.*s", topic, event->data_len, event->data);

        cJSON *root = cJSON_ParseWithLength(event->data, event->data_len);
        if (!root)
        {
            ESP_LOGW(TAG, "Payload is not valid JSON");
            return;
        }

        int code = cjson_get_int(root, "code");
        MessageType messageType = cjson_get_int(root, "messageType");

        if (code != 200)
        {
            ESP_LOGI(TAG, "JSON 'code' != 200 or missing — ignoring");
            cJSON_Delete(root);
            return;
        }
        switch (messageType)
        {
        case MOVE_CAR:
        {
            const cJSON *dataObj = cJSON_GetObjectItem(root, "data");
            handle_phone_MOVE_CAR(handle, messageType, dataObj);
            break;
        }
        case MOVE_CAMERA:
            ESP_LOGI(TAG, "[mt=2] Camera control message received (ignored in MQTT-only build)");
            break;
        case MOVE_MechanicalArm:
            ESP_LOGI(TAG, "[mt=3] Robot arm message received (ignored in MQTT-only build)");
            break;
        case PHONE_SET_DEVICE_ENABLE:
            ESP_LOGI(TAG, "[mt=4] enablePS2 flag received (ignored in MQTT-only build)");
            break;
        default:
            ESP_LOGI(TAG, "[mt=%d] Unhandled message type", messageType);
            break;
        }
        cJSON_Delete(root);
    }
    else
    {
        if (handle->mqtt_connect_callback)
        {
            handle->mqtt_connect_callback(handle, base, event_id);
        }
    }
}

void handle_phone_MOVE_CAR(MqttClient *handle, MessageType messageType, const cJSON *dataObj)
{
    if (!cJSON_IsObject(dataObj))
        return;
    bool leftRotate = cjson_get_bool(dataObj, "leftRotate");
    bool leftSlide = cjson_get_bool(dataObj, "leftSlide");
    bool rightRotate = cjson_get_bool(dataObj, "rightRotate");
    bool rightSlide = cjson_get_bool(dataObj, "rightSlide");
    float percentX = cjson_get_float(dataObj, "percentX");
    float percentY = cjson_get_float(dataObj, "percentY");

    // if (handle->mqtt_recv_msg_callback)
    //     handle->mqtt_recv_msg_callback(handle, messageType, &moveCar);
}

// 检查是否需要连接 MQTT 服务器
bool mqtt_connect_if_needed(MqttClient *handle, const char *mqttHost, int mqttPort)
{
    if (strlen(mqttHost) == 0 || mqttPort == 0)
    {
        ESP_LOGE(TAG, "mqttHost为空, mqttPort为0; 不能连接Mqtt");
        return false;
    }
    
    if (strncmp(handle->mqttHost, mqttHost, sizeof(handle->mqttHost)) == 0 &&
        handle->mqttPort == mqttPort)
    {
        ESP_LOGI(TAG, "已经连接到相同的 MQTT 服务器，无需重连: %s:%d", mqttHost, mqttPort);
        return false;
    }
    return true;
}

// Stops the MQTT client
void mqtt_client_stop(MqttClient *handle)
{
    if (!handle)
        return;
    if (!handle->client)
        return;
    if (!handle->mqttConnected)
        return;

    ESP_LOGE(TAG, "Stop Mqtt");

    memset(handle->mqttHost, 0, sizeof(handle->mqttHost));
    handle->mqttPort = 0;
    memset(handle->user_name, 0, sizeof(handle->user_name));
    memset(handle->password, 0, sizeof(handle->password));
    memset(handle->topic, 0, sizeof(handle->topic));
    handle->mqttConnected = false;
    esp_mqtt_client_stop(handle->client);
    esp_mqtt_client_destroy(handle->client);
}

// 销毁句柄
void destroy_mqtt(MqttClient *handle)
{
    if (!handle)
        return;
    if (handle->client && handle->mqttConnected == true)
    {
        esp_mqtt_client_stop(handle->client);
        esp_mqtt_client_destroy(handle->client);
    }
    free(handle);
}